﻿// Fill out your copyright notice in the Description page of Project Settings.


#include "MyEditorUtilityWidget.h"
#include "AssetData.h"
#include "EditorAnimUtils.h"
#include "Animation/Skeleton.h"
#include "HAL/FileManagerGeneric.h"
#include "Misc/Paths.h"
#include "Misc/LocalTimestampDirectoryVisitor.h"
#include "EditorAssetLibrary.h"

//#include "DesktopPlatform/Public/IDesktopPlatform.h"
//#include "DesktopPlatform/Public/DesktopPlatformModule.h"
//#include "Engine/GameEngine.h"
//#include "EngineGlobals.h"
//#include "SlateCore.h"
//#include "Runtime/Engine/Classes/Engine/GameViewportClient.h"
//#include "Framework/Application/SlateApplication.h"
//#include "Editor/UMGEditor/Public/WidgetBlueprint.h" 
//#include "Editor/LevelEditor/Public/LevelEditor.h" 
//#include "Runtime/Core/Public/Modules/ModuleManager.h" 
//#include "Editor/Blutility/Public/IBlutilityModule.h" 
//#include "Editor/Blutility/Classes/EditorUtilityWidgetBlueprint.h" 


//#include "Dialogs/Dialogs.h"
//#include "Dialogs/DlgPickPath.h"
//
//
//#include "IContentBrowserSingleton.h"
//#include "ContentBrowser/Public/ContentBrowserModule.h"

using namespace EditorAnimUtils;

void UMyEditorUtilityWidget::StartWidget(USkeleton* src, USkeleton* des, TArray<UAnimSequence*> sourceAsset, FString targetPrefix)
{

	TArray<TWeakObjectPtr<UObject>> AssetsToRetarget = TArray<TWeakObjectPtr<UObject>>();
	for (auto item : sourceAsset) {
		TWeakObjectPtr<UObject> wptr = TWeakObjectPtr<UObject>(item);
		AssetsToRetarget.Add(wptr);
	}
	
	FNameDuplicationRule rule;
	rule.Prefix = targetPrefix;
	rule.FolderPath.Append("/Retarget");
	FAnimationRetargetContext retarget(AssetsToRetarget, true, true, rule);

	
	UPackage * DuplicationDestPackage = des->GetOutermost();
	retarget.DuplicateAssetsToRetarget(DuplicationDestPackage,&rule);
	retarget.RetargetAnimations(src, des);	
}

TArray<UAnimSequence*> UMyEditorUtilityWidget::GetAllAssets(FString startPath)
{
	TArray<FString> AllFiles =  GetAllFilesInFolder(startPath,".uasset");
	
	return TArray<UAnimSequence*>();
}

TArray<FString> UMyEditorUtilityWidget::GetAllFilesInFolder(FString Directory, FString Extension)
{
	TArray<FString> output;
	output.Empty();
	if (FPaths::DirectoryExists(Directory))
	{
		FString path = Directory + Extension;
		FFileManagerGeneric::Get().FindFiles(output, *path, true, false);
	}
	return output;
}


/**
 Gets all the files in a given directory.
 @param directory The full path of the directory we want to iterate over.
 @param fullpath Whether the returned list should be the full file paths or just the filenames.
 @param onlyFilesStartingWith Will only return filenames starting with this string. Also applies onlyFilesEndingWith if specified.
 @param onlyFilesEndingWith Will only return filenames ending with this string (it looks at the extension as well!). Also applies onlyFilesStartingWith if specified.
 @return A list of files (including the extension).

 Usage example:

 FString directoryToSearch = TEXT("c:/YourGame/YourDir");
 FString filesStartingWith = TEXT("");
 FString fileExtensions = TEXT("sav");
 
 TArray filesInDirectory = GetAllFilesInDirectory(directoryToSearch, true, filesStartingWith, fileExtensions);

 */
TArray<FString> UMyEditorUtilityWidget::GetAllFilesInDirectory(const FString directory, const bool fullPath, const FString onlyFilesStartingWith, const FString onlyFilesWithExtension)
{
	// Get all files in directory
	TArray<FString> directoriesToSkip;
	IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
	FLocalTimestampDirectoryVisitor Visitor(PlatformFile, directoriesToSkip, directoriesToSkip, false);
	PlatformFile.IterateDirectory(*directory, Visitor);
	TArray<FString> files;

	


	for (TMap<FString, FDateTime>::TIterator TimestampIt(Visitor.FileTimes); TimestampIt; ++TimestampIt)
	{
		const FString filePath = TimestampIt.Key();
		const FString fileName = FPaths::GetCleanFilename(filePath);
		bool shouldAddFile = true;

		// Check if filename starts with required characters
		if (!onlyFilesStartingWith.IsEmpty())
		{
			const FString left = fileName.Left(onlyFilesStartingWith.Len());

			if (!(fileName.Left(onlyFilesStartingWith.Len()).Equals(onlyFilesStartingWith)))
				shouldAddFile = false;
		}

		// Check if file extension is required characters
		if (!onlyFilesWithExtension.IsEmpty())
		{
			if (!(FPaths::GetExtension(fileName, false).Equals(onlyFilesWithExtension, ESearchCase::IgnoreCase)))
				shouldAddFile = false;
		}

		// Add full path to results
		if (shouldAddFile)
		{
			files.Add(fullPath ? filePath : fileName);
		}
	}




	return files;
}

void UMyEditorUtilityWidget::GetRetargetPaths(const FString directory, const FString rule, TArray<FString>& originResult, TArray<FString>& ruleResult)
{
	//AnimSequence'/Game/Retarget/Shinbi_ThirdPersonIdle.Shinbi_ThirdPersonIdle'

	FString ProjectDir = FPaths::ProjectContentDir();
	FString AbsultePath = ProjectDir + directory;
	// Get all files in directory
	TArray<FString> directoriesToSkip;
	IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
	FLocalTimestampDirectoryVisitor Visitor(PlatformFile, directoriesToSkip, directoriesToSkip, false);
	PlatformFile.IterateDirectory(*AbsultePath, Visitor);

	FString extension(".uasset");

	for (TMap<FString, FDateTime>::TIterator TimestampIt(Visitor.FileTimes); TimestampIt; ++TimestampIt)
	{
		FString filePath = TimestampIt.Key();
		FString fileName = FPaths::GetCleanFilename(filePath);
		FString myFileName = FPaths::GetBaseFilename(filePath, false);
		myFileName.RemoveAt(0, ProjectDir.Len());


		

		FString origin_result("/Game/");
		origin_result.Append(myFileName);
		originResult.Add(origin_result);


		FString pathCopy(filePath);
		pathCopy.RemoveAt(filePath.Len() - (fileName.Len() + 1), (fileName.Len()+1));
		pathCopy.RemoveAt(0, ProjectDir.Len());

		FString rule_result("/Game/");
		rule_result.Append(rule);
		rule_result.Append(pathCopy);
		ruleResult.Add(rule_result);		
	}
}

void UMyEditorUtilityWidget::BatchRegarget(USkeleton* src, USkeleton* des,  const TArray<FString> originResult, const TArray<FString> ruleResult,const FString animPrefix)
{
	for (size_t i = 0; i < originResult.Num(); i++)
	{
		auto asset = UEditorAssetLibrary::LoadAsset(originResult[i]);
		if (asset == nullptr) continue;
		UAnimSequence* anim = Cast<UAnimSequence>(asset);
		if (anim == nullptr) continue;	
			TArray<TWeakObjectPtr<UObject>> AssetsToRetarget = TArray<TWeakObjectPtr<UObject>>();
			TWeakObjectPtr<UObject> wptr = TWeakObjectPtr<UObject>(anim);
			AssetsToRetarget.Add(wptr);

			FNameDuplicationRule rule;
			rule.Prefix = animPrefix;
			rule.FolderPath = ruleResult[i];
			FAnimationRetargetContext retarget(AssetsToRetarget, true, true, rule);
			UPackage* animPackage = des->GetOutermost();
			retarget.DuplicateAssetsToRetarget(animPackage, &rule);
			retarget.RetargetAnimations(src, des);
	}
	
}

void UMyEditorUtilityWidget::ProcessBatchRetarget()
{
	TArray<FString> originalPath = TArray<FString>();
	TArray<FString> copyPath = TArray<FString>();
	GetRetargetPaths(AnimFileRoot, CopyFileRoot, originalPath, copyPath);
	BatchRegarget(source, target, originalPath, copyPath, Prefix);
	FString SaveDir("/Game/");
	SaveDir.Append(CopyFileRoot);
	UEditorAssetLibrary::SaveDirectory(SaveDir);

	
}

void UMyEditorUtilityWidget::OpenSourceFolder()
{

	if (showSourcePath || showCopyPath) {
		return;
	}

	showSourcePath = true;
	FString Path = "/Game/"; // Trailing '/' is needed to set the default path
	{
		PickContentPathDlg =
			SNew(SDlgPickPath)
			.Title(FText::FromString("Choose Anim RootContentPath"))
			.DefaultPath(FText::FromString(Path));
		FSlateApplication::Get().AddWindow(PickContentPathDlg, true);
	}
}

void UMyEditorUtilityWidget::OpenTargetFolder()
{
	if (showSourcePath || showCopyPath) {
		return;
	}

	showCopyPath = true;
	FString Path = "/Game/"; // Trailing '/' is needed to set the default path
	{
		PickContentPathDlg =
			SNew(SDlgPickPath)
			.Title(FText::FromString("Choose Anim RootContentPath"))
			.DefaultPath(FText::FromString(Path));
		FSlateApplication::Get().AddWindow(PickContentPathDlg, true);
	}
}

void UMyEditorUtilityWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{

	Super::NativeTick(MyGeometry, InDeltaTime);


	if (showSourcePath) {
		const FString newPath = UMyEditorUtilityWidget::PickContentPathDlg->GetPath().ToString();
		OnSourceRootChange(newPath);
		FWidgetPath widgetPath;
		showSourcePath = FSlateApplication::Get().FindPathToWidget(UMyEditorUtilityWidget::PickContentPathDlg, widgetPath);
		if (!showSourcePath) {
			UE_LOG(LogTemp, Warning, TEXT("SoucePath Selected"));
		}
	}

	if (showCopyPath) {
		const FString newPath = UMyEditorUtilityWidget::PickContentPathDlg->GetPath().ToString();
		TargetRootChange(newPath);
		FWidgetPath widgetPath;
		showCopyPath = FSlateApplication::Get().FindPathToWidget(UMyEditorUtilityWidget::PickContentPathDlg, widgetPath);
		if (!showCopyPath) {
			UE_LOG(LogTemp, Warning, TEXT("CopyPath Selected"));
		}
	}
}

TSharedRef<SDlgPickPath> UMyEditorUtilityWidget::PickContentPathDlg = SNew(SDlgPickPath);
